<?php

namespace app\common\lib;
//微信公众号接口类
use app\common\model\AccountToken;
use think\facade\Log;

class WxUtil
{
    public $appId = '';
    public $appSecret = '';
    private static $_instance = null;
    private $url = "https://api.weixin.qq.com/cgi-bin/";

    public function __construct($appId, $appSecret)
    {
        $this->appId = $appId;
        $this->appSecret = $appSecret;
    }

    //单例模式
    public static function getInstance($appId, $appSecret)
    {
        if (empty(self::$_instance)) {
            self::$_instance = new self($appId, $appSecret);
        }
        return self::$_instance;
    }

    //获取access_token
    public function getAccessToken()
    {
        //查询是否存在
        $accountExist = AccountToken::where(['app_id' => $this->appId, 'app_secret' => $this->appSecret])
            ->field('access_token,access_token_expire_time')->find();
        //存在
        if ($accountExist) {
            // 没过期
            if (time() - $accountExist['access_token_expire_time'] < 0) {
                $accessToken = $accountExist['access_token'];
                return ['status' => 1, 'access_token' => $accessToken];
            }
        }
        $params = [
            'grant_type' => 'client_credential',
            'appid' => $this->appId,
            'secret' => $this->appSecret
        ];
        $url = $this->url . 'token?' . http_build_query($params);
        $result = Util::postCurl($url);
        if (isset($result['content']['errcode'])&&$result['content']['errcode']!=0) {
            return ['status' => -1, 'msg' => '获取access_token失败'];
        }
        if (isset($result['content']['access_token'])) {
            $accessToken = $result['content']['access_token'];
            $data = [
                'access_token' => $accessToken,
                'access_token_expire_time' => time() + 7200
            ];
        } else {
            return ['status' => -1, 'msg' => '获取access_token失败'];
        }
        if ($accountExist) {
            $res = AccountToken::update($data, ['app_id' => $this->appId, 'app_secret' => $this->appSecret]);
        } else {
            $data['app_id'] = $this->appId;
            $data['app_secret'] = $this->appSecret;
            $res = AccountToken::create($data);
        }
        if ($res) {
            return ['status' => 1, 'access_token' => $accessToken];
        } else {
            return ['status' => -1, 'msg' => '保存access_token失败'];
        }
    }

    //获取jsapi_ticket
    public function getJsapiTicket()
    {
        $accessTokenResult = $this->getAccessToken();
        if ($accessTokenResult['status'] == -1) {
            return ['status' => -1, 'msg' => '获取jsapi_ticket失败'];
        }
        $accessToken = $accessTokenResult['access_token'];
        $account = AccountToken::where(['app_id' => $this->appId, 'app_secret' => $this->appSecret])
            ->field('jsapi_ticket,jsapi_ticket_expire_time')->find();
        // 没过期
        if (time() - $account['jsapi_ticket_expire_time'] < 0) {
            $jsapiTicket = $account['jsapi_ticket'];
            return ['status' => 1, 'jsapi_ticket' => $jsapiTicket];
        }
        $url = $this->url . 'ticket/getticket?access_token=' . $accessToken . '&type=jsapi';
        $result = Util::postCurl($url);
        if (isset($result['content']['errcode'])&&$result['content']['errcode']!=0) {
            return ['status' => -1, 'msg' => '获取jsapi_ticket失败'];
        }
        if (isset($result['content']['ticket'])) {
            $jsapiTicket = $result['content']['ticket'];
            $data = [
                'jsapi_ticket' => $jsapiTicket,
                'jsapi_ticket_expire_time' => time() + 7200
            ];
        } else {
            return ['status' => -1, 'msg' => '获取jsapi_ticket失败'];
        }
        $res = AccountToken::update($data, ['app_id' => $this->appId, 'app_secret' => $this->appSecret]);
        if ($res) {
            return ['status' => 1, 'jsapi_ticket' => $jsapiTicket];
        } else {
            return ['status' => -1, 'msg' => '保存jsapi_ticket失败'];
        }
    }

    //获取js 微信转发分享参数
    //签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同
    public function getSignpackage(){
        $jsapiTicketResult = $this->getJsapiTicket();
        if ($jsapiTicketResult['status'] == -1) {
            return ['status' => -1, 'msg' => '获取jsapi_ticket失败'];
        }
        $jsapiTicket = $jsapiTicketResult['jsapi_ticket'];
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        $noncestr = $this->createNonceStr();
        $timestamp = time();
        $string = "jsapi_ticket={$jsapiTicket}&noncestr={$noncestr}&timestamp={$timestamp}&url={$url}";
        $signature = sha1($string);
        $signPackage = array(
            'appId'     => $this->appId,
            'nonceStr'  => $noncestr,
            'timestamp' => $timestamp,
            'signature' => $signature,
        );
        return $signPackage;
    }

    private function createNonceStr($length = 16) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    //发送模板消息
    public function sendTemplate($data){
        $accessTokenResult = $this->getAccessToken();
        if ($accessTokenResult['status'] == -1) {
            return ['status' => -1, 'msg' => '获取jsapi_ticket失败'];
        }
        $accessToken = $accessTokenResult['access_token'];
        $url = $this->url.'message/template/send?access_token='.$accessToken;
        $result = Util::postCurl($url,$data,[],'POST');
        if (isset($result['content']['errcode'])&&$result['content']['errcode']!=0) {
            return ['status' => -1, 'msg' => '获取access_token失败'];
        }
        return ['status' => 1, 'data' => $result['content']];
    }

}